#include <ArduinoHttpClient.h>
#include "simkai_20.h"

#include <ESP8266WiFi.h>
#include <WiFiManager.h>         //https://github.com/tzapu/WiFiManager

#include <NTPtimeESP.h>
#include <Ticker.h>
#include <ArduinoJson.h>
#include <TFT_eSPI.h>

#define NO_COUNT 0
#define MAX_COUNT 200

TFT_eSPI tft = TFT_eSPI();       // Invoke custom library

const char ssid[] = "Y5";      //WiFi名
const char pass[] = "87654321.";       //WiFi密码

NTPtime NTPch("ch.pool.ntp.org");   // Choose server pool as required

/*
 * The structure contains following fields:
 * struct strDateTime
{
  byte hour;
  byte minute;
  byte second;
  int year;
  byte month;
  byte day;
  byte dayofWeek;
  boolean valid;
};
 */
strDateTime dateTime;

Ticker ticker;// 建立Ticker用于实现定时功能
Ticker ticker2;

int year = 2010;
int month = 1;
int day = 1;
int hour = 0;
int minute = 0;
int second = 0;
int dayofWeek = 1;

int updateTimeCount = NO_COUNT;
boolean updateWeather = true;

const char weeks[][7] = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};

WiFiManager wifiManager;

char serverAddress[] = "api.seniverse.com";  // server address
int port = 80;

WiFiClient wifi;
HttpClient client = HttpClient(wifi, serverAddress, port);

const uint8_t PROGMEM f_icon[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x18,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x06,0xD8,0x06,0xD8,0x36,0xD8,0x36,0xD8,0x36,0xD8,0x36,0xD8,0x00,0x00,0x00,0x00};
const uint8_t PROGMEM t_icon[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x06,0xC0,0x06,0xC0,0x36,0xC0,0x36,0xC0,0x36,0xC0,0x36,0xC0,0x00,0x00,0x00,0x00};
const uint8_t PROGMEM s_icon[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x36,0x00,0x36,0x00,0x36,0x00,0x36,0x00,0x00,0x00,0x00,0x00};
const uint8_t PROGMEM o_icon[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00};
const uint8_t PROGMEM none_icon[] = {0x00,0x00,0x00,0x00,0x30,0x0C,0x38,0x1C,0x1C,0x38,0x0E,0x70,0x07,0xE0,0x03,0xC0,0x03,0xC0,0x07,0xE0,0x0E,0x70,0x1C,0x38,0x38,0x1C,0x30,0x0C,0x00,0x00,0x00,0x00};

struct MyWeather {

  String text;
  String temperature = "0";
};

MyWeather myWeather;

volatile byte state = HIGH;

void setup() {
  Serial.begin(9600);

  //Set up the display
  tft.init();
  tft.setRotation(0);
  tft.fillScreen(TFT_BLACK);
  
  // initWiFi();
  initWiFi2();
  
  // 每隔一秒钟调用time123函数一次，attach函数的第一个参数
  // 是控制定时间隔的变量。该参数的单位为秒。第二个参数是
  // 定时执行的函数名称。
  ticker.attach(1, clockTimer);
  ticker2.attach(7200, updateNetInfo);

  pinMode(D6, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(D6), clearWiFi, FALLING);
  
  tft.fillScreen(TFT_BLACK);
}

void loop() {
  if (updateWeather) {
    getWeather();
  }
  if (updateTimeCount < MAX_COUNT) {
    syncTime();
  }

  if (!state) {
    Serial.println("clear wifi");
    wifiManager.resetSettings();
    delay(2000);
    ESP.restart();
  }

  tft.setTextWrap(false);
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.setTextSize(1);
  tft.setCursor(0, 4);
  tft.print(year);
  tft.print("/");
  tft.printf("%02d", month);
  tft.print("/");
  tft.printf("%02d\n", day);

  int8_t rssi = WiFi.RSSI();
  if (rssi <= 0 && rssi >= -50) {
    tft.drawBitmap(112, 0, f_icon, 16, 16, TFT_GREEN, TFT_BLACK);
  } else if (rssi < -50 && rssi >= -70) {
    tft.drawBitmap(112, 0, t_icon, 16, 16, TFT_GREEN, TFT_BLACK);
  } else if (rssi < -70 && rssi >= -80) {
    tft.drawBitmap(112, 0, s_icon, 16, 16, TFT_YELLOW, TFT_BLACK);
  } else if (rssi < -80 && rssi >= -100) {
    tft.drawBitmap(112, 0, o_icon, 16, 16, TFT_YELLOW, TFT_BLACK);
  } else {
    tft.drawBitmap(112, 0, none_icon, 16, 16, TFT_RED, TFT_BLACK);
  }

  tft.drawLine(0, 16, 128, 16, TFT_WHITE);

  tft.setTextSize(2);
  tft.setTextColor(TFT_YELLOW, TFT_BLACK);
  tft.setCursor(16, 24);
  tft.printf("%02d", hour);
  tft.print(":");
  tft.printf("%02d", minute);
  tft.print(":");
  tft.printf("%02d\n", second);

  tft.loadFont(simkai_20);
  tft.setTextColor(TFT_WHITE, TFT_BLACK, true);
  tft.setCursor(0, 80);
  tft.print(myWeather.text);

  tft.drawLine(0, 100, 128, 100, TFT_WHITE);

  tft.setCursor(0, 104);
  tft.print(weeks[dayofWeek - 1]);

  int16_t tempW = tft.textWidth(myWeather.temperature + "℃");
  tft.setCursor(tft.getViewportWidth() - tempW, 104);
  tft.printf("%s℃", myWeather.temperature);

  tft.unloadFont();

}

void getWeather() {
  Serial.println("making GET request");
  client.get("/v3/weather/now.json?key=SAEmB0YvJBCPkzR3l&location=ip");

  // read the status code and body of the response
  int statusCode = client.responseStatusCode();
  Serial.print("Status code: ");
  Serial.println(statusCode);
  if (statusCode == 200) {
    String response = client.responseBody();
    response.trim();

    Serial.print("Response: ");
    Serial.println(response);

    DynamicJsonDocument doc(1024);
    deserializeJson(doc, response);

    String text = doc["results"][0]["now"]["text"];
    String temperature = doc["results"][0]["now"]["temperature"];
    Serial.println(text);
    Serial.println(temperature);

    myWeather.text = text;
    myWeather.temperature = temperature;
  }
  updateWeather = false;
}

void configModeCallback (WiFiManager *myWiFiManager) {
  Serial.println("Entered config mode");
  Serial.println(WiFi.softAPIP());

  Serial.println(myWiFiManager->getConfigPortalSSID());

  tft.setTextSize(1);
  tft.setCursor(0, 0);
  tft.println("Entered config mode");
  tft.println(WiFi.softAPIP());
  tft.println(myWiFiManager->getConfigPortalSSID());
}

//初始化WIFI
void initWiFi()
{
  Serial.print("Connecting WiFi...");

  WiFi.mode(WIFI_STA); //配置WIFI为Station模式
  WiFi.begin(ssid, pass); //传入WIFI热点的ssid和密码
  while (WiFi.status() != WL_CONNECTED) //等待连接成功
  {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP()); //打印自己的IP地址
}

void initWiFi2() {
  wifiManager.setAPCallback(configModeCallback);
  boolean ret = wifiManager.autoConnect();

  tft.fillScreen(TFT_BLACK);
  tft.setTextSize(1);
  tft.setCursor(0, 0);
  if (ret) {
    tft.println("wifi connected");
    tft.println(WiFi.localIP());
    delay(2000);
  }

}

void syncTime() {
  // first parameter: Time zone in floating point (for India); second parameter: 1 for European summer time; 2 for US daylight saving time; 0 for no DST adjustment; (contributed by viewwer, not tested by me)
  dateTime = NTPch.getNTPtime(8.0, 0);

  // check dateTime.valid before using the returned time
  // Use "setSendInterval" or "setRecvTimeout" if required
  if (dateTime.valid) {
    NTPch.printDateTime(dateTime);

    byte actualHour = dateTime.hour;
    byte actualMinute = dateTime.minute;
    byte actualsecond = dateTime.second;
    int actualyear = dateTime.year;
    byte actualMonth = dateTime.month;
    byte actualday = dateTime.day;
    byte actualdayofWeek = dateTime.dayofWeek;

    year = actualyear;
    month = actualMonth;
    day = actualday;
    hour = actualHour;
    minute = actualMinute;
    second = actualsecond;
    dayofWeek = actualdayofWeek;
    
    updateTimeCount = MAX_COUNT;
  } else {
    updateTimeCount++;
  }

}

void clockTimer() {
  second++;
  if (second > 59) {
    second = 0;
    minute++;
    if (minute > 59) {
      minute = 0;
      hour++;
      if (hour > 23) {
        hour = 0;
        dayofWeek++;
        if (dayofWeek > 7) {
          dayofWeek = 1;
        }
      }
    }
  }
}

void updateNetInfo() {
  updateWeather = true;
  updateTimeCount = NO_COUNT;
}

ICACHE_RAM_ATTR void clearWiFi() {
  state = LOW;
}

